package fr.orleans.tournament;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import javax.faces.application.FacesMessage;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ViewScoped;
import javax.faces.context.FacesContext;

import entities.Match;
import entities.Referee;
import entities.Team;
import entities.Tournament;
import enums.MatchStatus;
import enums.TournamentStatus;
import fr.orleans.tools.JSFServices;
import fr.orleans.tools.ManagedBeans;

@ManagedBean
@ViewScoped
public class AdminView extends ManagedBeans{

	private Tournament tournament;
	
	private List<Referee> listReferee;
	
	
	private List<Team> listTeams;
	private String tournamentTree;
	private List<Match> listMatchsSorted;

	public AdminView(){
		try{
			this.tournament = (Tournament) JSFServices.getParameterInRequestMap("tournament");
		}catch(Exception e){
			
		}
	}
	
	public Tournament getTournament() {
		if(tournament == null){
			tournament = (Tournament) JSFServices.getParameterInRequestMap("tournament");
		}
		return tournament;
	}

	public void setTournament(Tournament tournament) {
		this.tournament = tournament;
	}

	public List<Team> getListTeams() {
		if(listTeams == null)
			this.listTeams = new ArrayList<Team>(this.tournament.getListTeams());
		
		return listTeams;
	}

	public void setListTeams(List<Team> listTeams) {
		this.listTeams = listTeams;
	}

	public String getTournamentTree() {
		List<Match> listMatchSortedWithMatchNotYetDefine = getListMatchsSortedWithMatchNotYetDefine();
		/* Recherche du nombre de tours */
		int nbTours = (int) (Math.log(this.tournament.getListTeams().size()) / Math.log(2));
		int currentMatch = 1;
		/* Insertion des �quipes */
		String tree = "{";
		tree += "\"teams\":[";
		for(Match match : listMatchSortedWithMatchNotYetDefine){
			if(match.getRoundNumber() == 1){
				tree += "[";
				tree += "\"" + match.getHomeTeam().getName() + "\",\"" + match.getOutsideTeam().getName() + "\"";
				tree += "]";
				if(currentMatch != (this.getTournament().getListMatchs().size() / 2) + 1){
					tree += ",";
				}
				currentMatch ++;
			}
		}
		/* Insertion des resultats */
		tree += "],\"results\":[";
		int currentTour = 1;
		while(currentTour <= nbTours){
			currentMatch = 1;
			tree += "[";
			for(Match match : listMatchSortedWithMatchNotYetDefine){
				if(match.getRoundNumber() == currentTour){
					tree += "[";
					tree += match.getScoreHome() + "," + match.getScoreOutside();
					tree += "]";
					if(currentMatch != (this.getTournament().getListMatchs().size() / (2 * currentTour)) + 1){
						if(currentTour != nbTours)
							tree += ",";
					}
					currentMatch ++;
				}
			}
			tree += "]";
			if(currentTour != nbTours){
				tree += ",";
			}
			currentTour ++;
		}
		tree += "]}";
		this.tournamentTree = tree;
		return tournamentTree;
	}

	public void setTournamentTree(String tournamentTree) {
		this.tournamentTree = tournamentTree;
	}

	public List<Match> getListMatchsSorted() {
		if(listMatchsSorted == null){
			try{
				this.listMatchsSorted = new ArrayList<Match>();
				Iterator<Match> iterator = tournament.getListMatchs().iterator();
				while(iterator.hasNext()){
					Match match = iterator.next();
					if(match.getHomeTeam() != null && match.getOutsideTeam() != null){
						this.listMatchsSorted.add(match);
					}
				}
			}catch(Exception e){
				
			}
		}
		Collections.sort(listMatchsSorted);
		return listMatchsSorted;
	}

	public List<Match> getListMatchsSortedWithMatchNotYetDefine() {
		List<Match> listMatchSortedWithMatchNotYetDefine = new ArrayList<Match>();
		listMatchSortedWithMatchNotYetDefine = new ArrayList<Match>();
		Iterator<Match> iterator = tournament.getListMatchs().iterator();
		while(iterator.hasNext()){
			Match match = iterator.next();
			listMatchSortedWithMatchNotYetDefine.add(match);
		}
		Collections.sort(listMatchSortedWithMatchNotYetDefine);
		return listMatchSortedWithMatchNotYetDefine;
	}

	public void setListMatchsSorted(List<Match> listMatchsSorted) {
		this.listMatchsSorted = listMatchsSorted;
	}

	public String startTournament(){
		if(Long.bitCount(getListTeams().size()) == 1){
			Map<Integer, Team> mapTeam = new HashMap<Integer, Team>();
			for(Team team : getListTeams()){
				boolean ok = false;
				while(ok == false){
					int randomNumber = (int) (Math.random()*8);
					if(mapTeam.get(randomNumber) == null){
						mapTeam.put(randomNumber, team);
						ok = true;
					}
				}
			}
			int numMatch = 1;
			int numRound = 1;
			for(int i = 1; i < getListTeams().size(); i++){
				Match match = new Match();
				match.setMatchNumber(numMatch);
				match.setRoundNumber(numRound);
				match.setTournament(getTournament());
				match.setStatus(MatchStatus.preparation);
				if(numRound == 1){
					match.setHomeTeam(mapTeam.get((numMatch * 2) - 2));
					match.setOutsideTeam(mapTeam.get((numMatch * 2) -1));
				}
				numMatch ++;
				if(getListTeams().size()/(2*numRound) == getListTeams().size() - i){
					numRound ++;
					numMatch = 1;
				}
				getTournament().getListMatchs().add(match);
			}
			getTournament().setStatus(TournamentStatus.running);
			this.getService().getWebAction().editTournament(getTournament());
			this.tournament = this.getService().getWebAction().findTournament(this.tournament.getId());
			FacesContext.getCurrentInstance().addMessage("infoStartTournament", 
					new FacesMessage(FacesMessage.SEVERITY_INFO, "ok", "Le tirage au sort a ete effectue, le tournoi est lance !"));
		}
		else{
			FacesContext.getCurrentInstance().addMessage("infoStartTournament", 
					new FacesMessage(FacesMessage.SEVERITY_ERROR, "error", "Le nombre d'equipe doit etre une puissance de 2"));
		}
		return "";
	}

	public String editMatch(Match oneMatch){
		JSFServices.putParameterInRequestMap("match", oneMatch);
		return "/modules/match/adminEditMatch.xhtml";
	}

	public List<Referee> getListReferee() {
		if(this.listReferee == null)
			this.listReferee = new ArrayList<>(this.tournament.getListReferees());
			
		return listReferee;
	}

	public void setListReferee(List<Referee> listReferee) {
		this.listReferee = listReferee;
	}
}